home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers1.zip / DAVIDSYS.ASM < prev    next >
Assembly Source File  |  1992-01-23  |  49KB  |  1,698 lines

  1. page 58, 132
  2.  
  3. ;DBGINT3        equ    0
  4. ;DEBUG        equ    1        ; FOR NOW
  5. version        equ    5        ; version of this file
  6. s8005_version    equ    1        ; SEEQ 8005 stuff (not separate (yet))
  7.  
  8. ;version
  9. ; 1     = initially from Mark Dye
  10. ; 2     = Fix spin loop bug (cx=0 ->65536), broke on slower systems (6MHz)
  11. ; 3     = Fix '-n' bug, fix warnings
  12. ; 4     = Fix Compaq DOS bug (we must do STI after set_recv_isr)
  13. ;         Also, compile with DBGINT3 commmented out.
  14. ;         I thought that 0=false, 1=true, but they were IFDEFfed!
  15. ;         Also, Fix section to ignore broadcasts that we initiated
  16. ; 5     = Release version (nothing changed)
  17.  
  18. ;s8005_version
  19. ;  0    = Initially from MD
  20. ;  1    = Fix  8-bit insb bug (broke on 8088 PCs)
  21.  
  22.  
  23. ; Copyright 1991  DAVID Systems, Inc (Sunnyvale, CA) and Marc S Dye
  24. ; (d.b.a. ayuda Company - Camarillo, CA).  Distribution of this code
  25. ; including any derivation thereof, shall be made so as to afford the
  26. ; recipient of such distribution a copy of this source code, including
  27. ; any alterations, at no charge (except for copying, media, and shipping
  28. ; costs).  Any distribution of this source or derivations must contain
  29. ; this copyright notice.  Documentation describing this work or its
  30. ; derivations must acknowledge the copyright holders herein.  The names
  31. ; of the copyright holders may not be used to advertise, signify, or
  32. ; otherwise characterize any derived work, except for the aforementioned
  33. ; copyright acknowledgement.  This work is provided AS IS, with NO
  34. ; WARRANTIES expressed or implied, NOR any representations made as to
  35. ; its suitability or fitness for any purpose whatsoever.  The recipient
  36. ; assumes full responsibility for use of this work.
  37. ; Some patches made by:
  38. ;   Jeff Douglass
  39.  
  40. ifdef    DEBUG
  41. private        macro    SYM
  42.         public    SYM
  43.         endm
  44. else
  45. private        macro    SYM
  46.         endm
  47. endif
  48.  
  49.     include    defs.asm
  50. ; Ethernet-2 header length defined
  51. ;#
  52. ENET_HDR    equ    2*EADDR_LEN + 4  ;was +2
  53.  
  54. ; assemble a select few instructions (16-bit i/o) from the extended set
  55. ; otherwise, must do only 8086-compatible stuff!
  56.         .286p
  57.  
  58.  
  59. ; Definitions of interface to the SEEQ 8005 EDLC.  See the SEEQ data book
  60. ; for complete details of this device.
  61.  
  62. ; 8005 directly-addressable register offsets (from i/o base address)
  63. COMSTAT_R    equ    0        ; COMMAND / STATUS
  64. CONFIG1_R    equ    2        ; CONFIGURATION 1
  65. CONFIG2_R    equ    4        ; CONFIGURATION 2
  66. REA_PTR_R    equ    6        ; Receive End Area Pointer
  67. BUFWIN_R    equ    8        ; Buffer Window
  68. RX_PTR_R    equ    10        ; Receive Pointer
  69. TX_PTR_R    equ    12        ; Transmit Pointer
  70. DMA_ADDR_R    equ    14        ; DMA Address
  71.  
  72. ; 8005 COMMAND register
  73. DMA_INT_EN    equ    0001h
  74. RX_INT_EN    equ    0002h
  75. TX_INT_EN    equ    0004h
  76. WINDOW_INT_EN    equ    0008h
  77. DMA_INT_ACK    equ    0010h
  78. RX_INT_ACK    equ    0020h
  79. TX_INT_ACK    equ    0040h
  80. WINDOW_INT_ACK    equ    0080h
  81. SET_DMA_ON    equ    0100h
  82. SET_RX_ON    equ    0200h
  83. SET_TX_ON    equ    0400h
  84. SET_DMA_OFF    equ    0800h
  85. SET_RX_OFF    equ    1000h
  86. SET_TX_OFF    equ    2000h
  87. FIFO_READ    equ    4000h
  88. FIFO_WRITE    equ    8000h
  89.  
  90. ; 8005 STATUS register
  91. DMA_INT        equ    0010h
  92. RX_INT        equ    0020h
  93. TX_INT        equ    0040h
  94. WINDOW_INT    equ    0080h
  95. DMA_ON        equ    0100h
  96. RX_ON        equ    0200h
  97. TX_ON        equ    0400h
  98. FIFO_FULL    equ    2000h
  99. FIFO_EMPTY    equ    4000h
  100. FIFO_DIR    equ    8000h
  101.  
  102. ; 8005 CONFIGURATION 1 register
  103. MATCH_BITS_M    equ    0C000h
  104. MATCH_ONLY    equ    0000h
  105. MATCH_BROAD    equ    4000h
  106. MATCH_MULTI    equ    8000h
  107. MATCH_ALL    equ    0C000h
  108. ALL_STATIONS    equ    3F00h
  109. STATION_0_EN    equ    0100h
  110. STATION_1_EN    equ    0200h
  111. STATION_2_EN    equ    0400h
  112. STATION_3_EN    equ    0800h
  113. STATION_4_EN    equ    1000h
  114. STATION_5_EN    equ    2000h
  115. DMA_LENGTH_M    equ    00C0h
  116. NBYTES_1    equ    0000h
  117. NBYTES_2    equ    0040h
  118. NBYTES_4    equ    0080h
  119. NBYTES_8    equ    00C0h
  120. DMA_INTERVAL_M    equ    0030h
  121. CONTINUOUS    equ    0000h
  122. DELAY_800    equ    0010h
  123. DELAY_1600    equ    0020h
  124. DELAY_3200    equ    0030h
  125. BUFFER_CODE_M    equ    000Fh
  126. STATION_0_SEL    equ    0000h
  127. STATION_1_SEL    equ    0001h
  128. STATION_2_SEL    equ    0002h
  129. STATION_3_SEL    equ    0003h
  130. STATION_4_SEL    equ    0004h
  131. STATION_5_SEL    equ    0005h
  132. PROM_SEL    equ    0006h
  133. TEA_SEL        equ    0007h
  134. BUFFER_MEM_SEL    equ    0008h
  135. INT_VECTOR_SEL    equ    0009h
  136. ; Ether-T PC/AT device configuration register -- access is overloaded onto
  137. ; the set of registers accessible via the reserved range in CONFIGURATION 1
  138. CARD_CONFIG_SEL    equ    000Fh
  139. SET_16BITMODE_M    equ    0080h        ; OR mask for 16 bit mode
  140.  
  141. ; 8005 CONFIGURATION 2 register
  142. BYTE_SWAP    equ    0001h
  143. AUTO_UPDATE_REA    equ    0002h
  144. CRC_ERR_EN    equ    0008h
  145. DRIBBLE_EN    equ    0010h
  146. SHORT_FRAME_EN    equ    0020h
  147. SLOT_TIME_SEL    equ    0040h
  148. XMIT_NO_PREAM    equ    0080h
  149. ADDR_LENGTH    equ    0100h
  150. RECEIVE_CRC    equ    0200h
  151. XMIT_NO_CRC    equ    0400h
  152. LOOPBACK_EN    equ    0800h
  153. KILL_WATCHDOG    equ    1000h
  154. RESET        equ    8000h
  155.  
  156. ; 8005 TRANSMIT HEADER COMMAND BYTE  (byte 3 of transmit packet header)
  157. BABBLE_INT_EN    equ    01h
  158. COLL_INT_EN    equ    02h
  159. COLL_16_INT_EN    equ    04h
  160. XMIT_OK_INT_EN    equ    08h
  161. DATA_FOLLOWS    equ    20h        ; also in RECEIVE HEADER COMMAND BYTE
  162. CHAIN_CONTINUE    equ    40h        ; also in RECEIVE HEADER COMMAND BYTE
  163. PACKET_PRESENT    equ    80h
  164. TX_HEADER_Z    equ    4        ; # of bytes in a TX header
  165.  
  166. ; 8005 TRANSMIT HEADER STATUS BYTE  (byte 4 of transmit packet header)
  167. BABBLE_ERR    equ    01h
  168. COLL        equ    02h
  169. COLL_16_ERR    equ    04h
  170. HDR_DONE    equ    80h
  171.  
  172. ; 8005 RECEIVE HEADER COMMAND BYTE (byte 3 of receive packet header)
  173. ;DATA_FOLLOWS        20h        from TRANSMIT HEADER COMMAND BYTE
  174. ;CHAIN_CONTINUE        40h        from TRANSMIT HEADER COMMAND BYTE
  175.  
  176. ; 8005 RECEIVE HEADER STATUS BYTE (byte 4 of receive packet header)
  177. OVERSIZE    equ    01h
  178. CRC_ERR        equ    02h
  179. DRIBBLE_ERR    equ    04h
  180. SHORT_FRAME    equ    08h
  181.  
  182. ; 8005 Receive Area Base Pointer
  183. RCV_PTR        equ    ((4 + GIANT + 4 + 255) AND NOT 0FFh)
  184. ; 8005 Transmit End Area Pointer (upper 8-bits)
  185. TEA_INIT    equ    (((RCV_PTR - 1) / 256) AND 0FFh)
  186.  
  187. ; macro to provide a delay after dinking w/ 8005 registers
  188. io_delay    macro    CNTVAR
  189.         local    io_delay_loop, skip_delay
  190.         push    cx
  191.         mov    cx, CNTVAR
  192.                 jcxz    skip_delay
  193. io_delay_loop:    nop
  194.         loop    io_delay_loop
  195. skip_delay:    pop    cx
  196.         endm
  197.  
  198. ; macros to get and set the various device registers
  199. ; these assume that a proper 'loadport' context exists, that input/output
  200. ; register values are in AX (for word i/o) or AL (for byte i/o)
  201. get_r        macro    R
  202.         setport    R
  203.         call    inb_8005
  204.         endm
  205.  
  206. getw_r        macro    R
  207.         setport    R
  208.         call    [inw_fn]
  209.         endm
  210.  
  211. set_r        macro    R
  212.         setport    R
  213.         call    outb_8005
  214.         endm
  215.  
  216. setw_r        macro    R
  217.         setport    R
  218.         call    [outw_fn]
  219.         endm
  220.  
  221. ; wait for the 8005 FIFO to be free
  222. fifo_wait    macro
  223.         local    fifo_wait_loop
  224.         setport    COMSTAT_R    ; fix access within the loop
  225. fifo_wait_loop:    getw_r    COMSTAT_R    ; wait for the FIFO to be free to use
  226.         and    ax, FIFO_EMPTY+FIFO_DIR
  227.         cmp    ax, FIFO_EMPTY
  228.         jne    fifo_wait_loop    ; loop
  229.         endm
  230.  
  231.  
  232. CODE    segment    byte public
  233.     assume    cs:CODE, ds:CODE
  234.  
  235.     public    INT_NO, IO_ADDR
  236. INT_NO        db    3, 0, 0, 0    ; interrupt number
  237. IO_ADDR        dw    300h, 0        ; (factory) i/o port address
  238.  
  239.     public    DRIVER_CLASS, DRIVER_TYPE, DRIVER_NAME, DRIVER_FUNCTION
  240.     public    PARAMETER_LIST, INT_NUM
  241. DRIVER_CLASS    db    BLUEBOOK, 0, 0
  242. DRIVER_TYPE    db    70        ; Ether-T PC/AT, specifically
  243. DRIVER_NAME    db    "Ether-T PC/AT", 0  ; name of the driver
  244. DRIVER_FUNCTION    db    2        ; standard plus extensions (except
  245.                     ;  specific multicast)
  246. PARAMETER_LIST    label    byte
  247.         db    1        ; major rev of packet driver spec
  248.         db    9        ; minor rev of packet driver spec
  249.         db    14        ; length of parameter list
  250.         db    EADDR_LEN    ; length of MAC-layer address
  251.         dw    GIANT        ; MTU, including headers
  252.         dw    MAX_MULTICAST * EADDR_LEN
  253.                     ; buffer size of multicast addresses
  254.         dw    0        ; (# of back-to-back MTU recvs) - 1
  255.         dw    0        ; (# of successive xmits) - 1
  256. INT_NUM        dw    0        ; interrupt # to hook for post-EOI
  257.                     ;  processing, 0 == none
  258.  
  259.     public    RCV_MODES
  260. ; Receive mode set-up dispatch table.  Refers to actual code frags below that 
  261. ; do the job.
  262. RCV_MODES    dw    7        ; number of receive modes in our table
  263.         dw    0        ; none exists
  264.         dw    rcv_mode_1    ; receiver off
  265.         dw    rcv_mode_2    ; only packets for this station
  266.         dw    rcv_mode_3    ; mode 2 plus broadcast
  267.         dw    0        ; mode 3 plus limited multicast
  268.         dw    rcv_mode_5    ; mode 3 plus all multicast
  269.         dw    rcv_mode_6    ; all packets
  270.  
  271. ; per-device instance structures -- keep state of the device -- ones marked
  272. ; as (copy) are soft copies of things actually on the device
  273.     private    command_r
  274. command_r    dw    0        ; COMMAND (copy, sort of)
  275.     private    config1_r_copy
  276. config1_r_copy    dw    0        ; CONFIGURATION 1 (copy)
  277.     private    config2_r_copy
  278. config2_r_copy    dw    0        ; CONFIGURATION 2 (copy)
  279.     private    cardconfig_r
  280. cardconfig_r    db    0        ; CARD CONFIGURATION (copy)
  281.     private    rcv_errors
  282. rcv_errors    db    0        ; want to receive even flawed packets
  283.     private    rcv_ptr_copy
  284. rcv_ptr_copy        dw    0        ; current (next) received packet ptr
  285.     private    transmit
  286. transmit    db    0        ; currently transmitting
  287.         db    ?
  288. station_0       db      6 dup(0)        ;current address (for disallowing
  289.                                         ; broadcast packets)(JLD)(9-25-91)
  290.  
  291. ; i/o instruction processing variables
  292.     private    delay_mult
  293. delay_mult    dw    10, 0        ; delay multiplier / divisor - is
  294.                     ; a tens fraction: delay becomes
  295.                     ; (calibrated_delay * delay_mult) / 10
  296.     private    io_16
  297. io_16        db    0        ; do 16-bit i/o?
  298.         db    ?
  299.     private    io_delay_cnt
  300. io_delay_cnt    dw    1, 0        ; # of NOP spins to do to effect the
  301.                     ; required delay (2000 ns) for the
  302.                     ; worst-case i/o access
  303.     private    iowm_delay_cnt
  304. iowm_delay_cnt    dw    1, 0        ; # of NOP spins to effect the required
  305.                     ; delay (800 ns) for a write to the
  306.                     ; buffer memory in the window register
  307.     private    inw_fn
  308. inw_fn        dw    OFFSET inwb_8005  ; function to input a word (w/ delay)
  309.     private    outw_fn
  310. outw_fn        dw    OFFSET outwb_8005 ; function to output a word (w/ delay)
  311.  
  312. ; interrupt processing variables
  313.     private    int_test
  314. int_test    db    0        ; in the initial interrupt testing?
  315.     private    int_tested
  316. int_tested    db    0        ; was initial interrupt test successful?
  317.  
  318. ifdef    DEBUG
  319.     public    ghost_int_c, send_wait_c
  320. ghost_int_c    dw    0        ; ghost (empty) interrupt counter
  321. rx_restart    dw    0        ; stalled receiver restart counter
  322. send_wait_c    dw    0        ; previous send completion wait counter
  323. endif
  324.  
  325.     extrn    THEIR_ISR : dword
  326.  
  327.     extrn    COUNT_IN_ERR : near
  328.     extrn    COUNT_OUT_ERR : near
  329.     extrn    GET_NUMBER : near
  330.     extrn    MASKINT : near
  331.     extrn    PRINT_NUMBER : near
  332.     extrn    RECV_COPY : near
  333.     extrn    RECV_FIND : near
  334.     extrn    SET_RECV_ISR : near
  335.     extrn    UNMASKINT : near
  336.  
  337.  
  338.     public    AS_SEND_PKT
  339. ; Asynchronous packet transmit routine (high-performance drivers only).
  340. ; Entry with:
  341. ;    ES:DI    control block pointer
  342. ;    DS:SI    packet to send
  343. ;    CX    packet length
  344. ; Interrupts *may* be enabled.  Returns:
  345. ;    ES:DI    preserved from call (control block pointer)
  346. ;       and
  347. ;    NC    if OK
  348. ;       or
  349. ;    CY    if transmission error
  350. ;    DH    error code
  351. ; Interrupt disablement on entry is preserved on exit.
  352. AS_SEND_PKT:
  353.         assume    ds:nothing
  354.         ret
  355.  
  356.  
  357.     public    DROP_PKT
  358. ; Drop a packet from the queue (high-performance drivers only.)
  359. DROP_PKT:
  360.         assume    ds:nothing
  361.         ret
  362.  
  363.  
  364.     public    GET_ADDRESS
  365. ; Get the MAC-layer address of the device.  Entry with:
  366. ;    ES:DI    spot to plop the gotten address
  367. ;    CX    size of the address buffer at ES:DI
  368. ; Returns:
  369. ;    NC    if OK
  370. ;    CX    actual size of address gotten
  371. ;       or
  372. ;    CY    if buffer not big enough
  373. GET_ADDRESS:
  374.         assume    ds:CODE
  375.         cmp    cx, EADDR_LEN    ; make sure there's enough room
  376.         jb    get_address_err
  377.         mov    cx, EADDR_LEN    ; prepare to copy 6 bytes
  378.  
  379.         ; mask receiver interrupts (note the receiver is still
  380.         ;   running however) -- this also arbitrates use of the FIFO
  381.         push    cx        ; push stuff so MASKINT won't bite us
  382.         mov    al, INT_NO
  383.         call    MASKINT
  384.         pop    cx        ; revive stuff pushed for MASKINT
  385.  
  386.         ; get the station address
  387.         loadport
  388.         mov    ax, config1_r_copy    ; select STATION address reg 0
  389.         or    ax, STATION_0_SEL
  390.         setw_r    CONFIG1_R
  391.         xor    ax, ax
  392.         setw_r    DMA_ADDR_R
  393.         setport    BUFWIN_R    ; fix access within the loop
  394. GET_ADDRESS_1:    get_r    BUFWIN_R    ; input bytes of the address
  395.         mov    es:[di], al
  396.         inc    di
  397.         loop    GET_ADDRESS_1
  398.  
  399.         ; unmask receiver interrupts, releasing FIFO
  400.         mov    al, INT_NO
  401.         call    UNMASKINT
  402.  
  403.         mov    cx, EADDR_LEN    ; return the length copied
  404.         clc            ; OK
  405.         ret
  406.  
  407. get_address_err:
  408.         stc            ; error
  409.         ret
  410.  
  411.  
  412.     private    inb_8005
  413. ; input a byte from an arbitrary 8005 port
  414. inb_8005:
  415.         assume    ds:nothing
  416.         in    al, dx
  417.         io_delay  io_delay_cnt    ; generic delay
  418.         ret
  419.  
  420.  
  421.     private    inwb_8005
  422. ; input a word from an arbitrary 8005 port -- 8 bit version
  423. inwb_8005:
  424.         assume    ds:nothing
  425.         in    al, dx
  426.         io_delay  io_delay_cnt    ; generic delay
  427.         inc    dx
  428.         xchg    al, ah
  429.         in    al, dx
  430.         xchg    al, ah
  431.         io_delay  io_delay_cnt    ; generic delay
  432.         dec    dx        ; to keep 'setport' in synch
  433.         ret
  434.  
  435.  
  436.     private    inw_8005
  437. ; input a word from an arbitrary 8005 port -- 16 bit version
  438. inw_8005:
  439.         assume    ds:nothing
  440.         in    ax, dx
  441.         io_delay  io_delay_cnt    ; generic delay
  442.         ret
  443.  
  444.  
  445.     private    outb_8005
  446. ; output a byte to an arbitrary 8005 port
  447. outb_8005:
  448.         assume    ds:nothing
  449.         out    dx, al
  450.         io_delay  io_delay_cnt    ; generic delay
  451.         ret
  452.  
  453.  
  454.     private    outwb_8005
  455. ; output a word to an arbitrary 8005 port -- 8 bit version
  456. outwb_8005:
  457.         assume    ds:nothing
  458.         out    dx, al
  459.         io_delay  io_delay_cnt    ; generic delay
  460.         inc    dx
  461.         xchg    al, ah
  462.         out    dx, al
  463.         xchg    al, ah
  464.         io_delay  io_delay_cnt    ; generic delay
  465.         dec    dx        ; to keep 'setport' in synch
  466.         ret
  467.  
  468.  
  469.     private    outw_8005
  470. ; output a word to an arbitrary 8005 port -- 16 bit version
  471. outw_8005:
  472.         assume    ds:nothing
  473.         out    dx, ax
  474.         io_delay  io_delay_cnt    ; generic delay
  475.         ret
  476.  
  477.  
  478.     private    rcv_mode_1
  479.     private    rcv_mode_2
  480.     private    rcv_mode_3
  481.     private    rcv_mode_5
  482.     private    rcv_mode_6
  483. ; Receive mode set-up routines.  Dispatched to out of the RCV_MODES
  484. ; switch (above) or called directly by ETOPEN (once).
  485.         assume    ds:CODE
  486. rcv_mode_1:    ; turn off receiver
  487.         call    turn_rx_off
  488.         ret
  489. rcv_mode_2:    ; only packets to this station address
  490.         mov    ax, MATCH_ONLY    ; config 1
  491.         mov    dx, 0        ; config 2
  492.         jmp    SHORT rcv_mode_common
  493. rcv_mode_3:    ; mode 2 plus broadcast packets
  494.         mov    ax, MATCH_BROAD    ; config 1
  495.         mov    dx, CRC_ERR_EN+DRIBBLE_EN+SHORT_FRAME_EN ; config 2
  496.         jmp    SHORT rcv_mode_common
  497. rcv_mode_5:    ; mode 3 plus all multicast packets
  498.         mov    ax, MATCH_MULTI    ; config 1
  499.         mov    dx, CRC_ERR_EN+DRIBBLE_EN+SHORT_FRAME_EN ; config 2
  500.         jmp    SHORT rcv_mode_common
  501. rcv_mode_6:    ; all packets (promiscuous, including errors)
  502.         mov    ax, MATCH_ALL    ; config 1
  503.         mov    dx, CRC_ERR_EN+DRIBBLE_EN+SHORT_FRAME_EN ; config 2
  504. rcv_mode_common:
  505.         push    dx        ; save the changes while we
  506.         push    ax        ;   wang on the receiver
  507.         call    turn_rx_off        ; shut down whilst we play
  508.         loadport
  509.         pop    bx        ; alter the CONFIGURATION 1 register
  510.         mov    ax, config1_r_copy
  511.         and    ax, NOT MATCH_BITS_M
  512.         or    ax, bx
  513.         mov    rcv_errors, 0
  514.         cmp    bx, MATCH_ALL    ; figure if we want to see errors
  515.         jne    rcv_mode_common_1
  516.         mov    rcv_errors, 1
  517. rcv_mode_common_1:
  518.         mov    config1_r_copy, ax
  519.         setw_r    CONFIG1_R
  520.         pop    bx        ; alter the CONFIGURATION 2 register
  521.         mov    ax, config2_r_copy
  522.         and    ax, NOT (CRC_ERR_EN+DRIBBLE_EN+SHORT_FRAME_EN)
  523.         or    ax, bx
  524.         mov    config2_r_copy, ax
  525.         setw_r    CONFIG2_R
  526.         call    turn_rx_on        ; drop trou now, brown cow
  527.         ret
  528.  
  529.  
  530.     private    turn_rcv_on
  531. ; turn the receiver back on, as per the COMMAND register atop the stack
  532. ; removes the COMMAND register upon return
  533. rcv_on:
  534.         assume    ds:CODE
  535.         mov    bx, sp        ; get former COMMAND register
  536.         mov    ax, ss:[bx+2]
  537.         test    ax, SET_RX_OFF    ; see if it's to go back on
  538.         jnz    rcv_on_1
  539.         mov    command_r, ax    ; restore it
  540.         call    turn_rx_on
  541. rcv_on_1:    ret    2        ; clear stack of COMMAND register too
  542.  
  543.  
  544.     private    rcvxmt_off
  545. ; forcibly turn off the receiver and/or transmitter -- if the transmitter
  546. ; is running, this will abort the transmission
  547. ; leaves the prior COMMAND register on top of the stack (for use by a
  548. ; matching 'rcv_on' call)
  549. rcvxmt_off:
  550.         assume    ds:CODE
  551.         pop    bx        ; return address
  552.         push    command_r    ; left for 'rcv_on'
  553.         or    command_r, SET_TX_OFF
  554.         mov    transmit, 0    ; not doing it now
  555.         call    turn_rx_off
  556.         jmp    bx        ; return
  557.  
  558.  
  559.     public    RECV
  560. ; Part one of the ISR receive packet processing.  Called before interrupt
  561. ; acknowledgement.  All registers have been saved, DS == CS, and we're
  562. ; running on a private stack with interrupts disabled.
  563. RECV:
  564.         assume    ds:CODE
  565. ifdef    DBGINT3
  566.         int    03h        ; Danger, Will Robinson!
  567. endif
  568.         loadport
  569.         ; check for and acknowledge the 8005 receive Interrupt
  570. ifdef    DEBUG
  571.         getw_r    COMSTAT_R
  572.         test    ax, RX_INT
  573.         jnz    recv_1
  574.         inc    ghost_int_c    ; ghost interrupt counter
  575. recv_1:
  576. endif
  577.         mov    ax, command_r    ; acknowledge the Rx Interrupt
  578.         or    ax, RX_INT_ACK
  579.         setw_r    COMSTAT_R
  580.         cmp    int_test, 0    ; is this interrupt a test one?
  581.         je    recv_setup
  582.         inc    int_tested    ; indicated tested and be done
  583.         ret
  584.  
  585. recv_setup:    ; set-up DMA access of the buffer read memory
  586.         mov    ax, config1_r_copy    ; select BUFFER MEMORY in BUFWIN
  587.         or    ax, BUFFER_MEM_SEL
  588.         setw_r    CONFIG1_R
  589.  
  590.         setport    DMA_ADDR_R    ; code block port state synch
  591. ; COME HERE w/ port @ DMA_ADDR_R
  592. recv_rcvptr:    mov    ax, rcv_ptr_copy    ; address the next RECEIVE HEADER
  593.         setw_r    DMA_ADDR_R
  594.         mov    ax, command_r    ; set the FIFO to READ now
  595.         or    ax, FIFO_READ
  596.         setw_r    COMSTAT_R
  597.  
  598.         setport    BUFWIN_R    ; code block port state synch
  599. ; COME HERE w/ port @ BUFWIN_R
  600. recv_loop:    ; check for an end-of-list header (0 next pointer)
  601.         getw_r    BUFWIN_R    ; get the HEADER pointer
  602.         cmp    al, 0        ; check for end of receive list
  603.         je    recv_loop_1    ;  looking only at first byte
  604.         xchg    al, ah        ; swap to proper host order
  605.         mov    cx, ax        ; save pointer away
  606.         getw_r    BUFWIN_R    ; get the HEADER & PACKET STATI
  607.         test    al, CHAIN_CONTINUE  ; test for completion
  608.         xchg    al, ah        ; AL now holds PACKET STATUS byte
  609.         jnz    recv_continue
  610. recv_loop_1:    jmp    recv_done
  611.  
  612. recv_continue:    ; process a new frame - compute length and check it
  613.         push    cx        ; squirrel away HEADER POINTER
  614.         sub    cx, rcv_ptr_copy    ; compute length, checking for wrappage
  615.         jae    recv_continue_1
  616.         sub    cx, RCV_PTR    ; adjust for wrap, sans xmit area
  617. recv_continue_1:
  618.         sub    cx, 4        ; less size of 8005 garf
  619.         cmp    cx, ENET_HDR    ; < a header is tallied and pitched
  620.         jb    recv_continue_2
  621.         cmp    cx, GIANT    ; > GIANT likewise
  622.         ja    recv_continue_2
  623.         test    al, SHORT_FRAME+DRIBBLE_ERR+CRC_ERR
  624.         jz    recv_alloc    ; no error is a-OK
  625.         cmp    rcv_errors, 0    ; see if we have to allow bad ones
  626.         jne    recv_alloc    ; yes, keep this dreck too
  627. recv_continue_2:
  628.         call    COUNT_IN_ERR    ; tally this error
  629.         jmp    recv_sail_it
  630.  
  631. recv_alloc:    ; this one we want - allocate enough space on the stack
  632.         ;  to hold the Ethernet-2 packet header (so we can upcall
  633.         ;  pointing at the type field)
  634.         mov    bx, cx        ; save the real length
  635.         mov    cx, ENET_HDR
  636.         sub    sp, cx        ; allocate a header on the stack
  637.         mov    di, sp        ;   and point at it w/ DI
  638.         mov    ax, ss        ; set-up ES too
  639.         mov    es, ax
  640.         cmp    io_16, 0    ; do we do it fast or slow?
  641.         je    recv_8bit_hdr
  642.         sar    cx, 1        ; turn into words
  643. ;    rep    insw
  644. recv_16bit_hdr:
  645.         insw            ; 16-bit input    
  646.         io_delay iowm_delay_cnt    ; reduced delay w/i loop
  647.         loop    recv_16bit_hdr
  648.         jmp    SHORT recv_upcall1
  649. recv_8bit_hdr:                ; 8-bit input
  650.         in    al, dx
  651.         mov    es:[di], al
  652.         inc    di
  653.         loop    recv_8bit_hdr
  654.  
  655. recv_upcall1:
  656. ;#              ; check to make sure this isn't our own broadcast(JLD)(9-25-91)
  657.                 push    di
  658.             mov    di, sp        ; point at the destination
  659.                 add     di, 2           ; which is 2 bytes away(remember push di?)
  660.                 mov     ax, 0ffffh
  661.                 mov     cx, 6/2
  662.             repe scasw
  663.                 jne     NotBroadcast
  664.             
  665.                 push    si
  666.                 mov     si, offset station_0
  667.                 mov     cx, 6/2
  668.             repe cmps   word ptr cs:[si], word ptr es:[di]
  669.                 pop     si
  670.             
  671.                 jne     NotBroadcast
  672.  
  673.                 pop     di
  674.         add    sp, ENET_HDR    ; pop the Ethernet-2 header from stack
  675.                                         ; I forgot this until it bit me (11-6)
  676.                 jmp     recv_sail_it    ; if it's us, bail out!
  677. NotBroadcast:
  678.                 pop     di
  679.  
  680.  
  681.                 ; prepare an upcall with CX == length, ES:DI pointing at type,
  682.         ;  DL == packet class number (V8)
  683.         mov    di, sp        ; point at the type field
  684.         add    di, EADDR_LEN*2
  685.         mov    cx, bx        ; get the real length for RECV_FIND
  686.         push    bx        ; save the real length
  687.         push    dx        ;  and save our precious port setup too
  688. ;#
  689.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  690.     mov    ax, es:[di]
  691.     xchg    ah, al
  692.     cmp     ax, 1500
  693.     ja    BlueBookPacket
  694.     inc    di            ;set di to 802.2 header
  695.     inc    di
  696.     mov    dl, IEEE8023
  697. BlueBookPacket:
  698. ;;;;        mov    dl, BLUEBOOK    ; Ethernet-2 'Bluebook' (V8)
  699.         call    RECV_FIND
  700.  
  701.         pop    dx        ; get back port setup
  702.         pop    bx        ;  and true packet length
  703.         mov    ax, es        ; see if the client passed on this one
  704.         or    ax, di
  705.         jz    recv_sail_pop
  706.  
  707.         mov    si, sp        ; prepare to MOVS the Ethernet-2 header
  708.         mov    ax, ss
  709.         mov    ds, ax
  710.         assume    ds:nothing
  711.         mov    cx, ENET_HDR
  712.         push    di        ; save client packet base pointer
  713.     rep    movsb
  714.         pop    si        ; restore client packet base pointer
  715.         add    sp, ENET_HDR    ; pop the Ethernet-2 header from stack
  716.  
  717.         mov    cx, bx        ; compute residual length to bring in
  718.         sub    cx, ENET_HDR
  719.         cmp    io_16, 0    ; do we do it fast or slow?
  720.         je    recv_8bit_data
  721.  
  722.         sar    cx, 1        ; /2: compute # of words to transfer
  723. ;    rep    insw            ; loosely termed "full-bandwidth i/o"
  724. recv_16bit_data:
  725.         insw
  726.         io_delay iowm_delay_cnt    ; reduced delay w/i loop
  727.         loop    recv_16bit_data
  728.  
  729.         mov    cx, bx        ; get length back one more time
  730.         test    bl, 1        ; see if there's a dangling byte
  731.         jz    recv_upcall2
  732.         mov    cx, 1        ; set-up to fall through to 8-bit
  733.  
  734. recv_8bit_data:    in    al, dx
  735.         mov    es:[di], al
  736.         inc    di
  737.         loop    recv_8bit_data
  738.         mov    cx, bx        ; get length back one more time
  739.         xor    bl, bl        ; for sail testing after upcall2
  740.  
  741. recv_upcall2:    ; prepare an upcall with CX == length, DS:SI pointing at
  742.         ;  client-allocated and now filled packet
  743.         mov    ax, es
  744.         mov    ds, ax
  745.         push    dx        ; save our precious port setup
  746.  
  747.         call    RECV_COPY
  748.  
  749.         pop    dx        ; get back port setup
  750.         mov    ax, cs        ;  and set DS back to CODE
  751.         mov    ds, ax
  752.         assume    ds:CODE
  753.  
  754.         ; have to check if 16-bit i/o processed an odd-length packet
  755.         ;  - if so, we MAY have blown the harmony of the 8005 DMA
  756.         ;  (may now be off by one) so just sail it
  757.         test    bl, 1
  758.         jnz    recv_sail_it
  759.  
  760.         pop    cx        ; pop squirreled next HEADER POINTER
  761.         mov    rcv_ptr_copy, cx    ;  and make that the new pointer
  762.         mov    al, ch        ; update the REA PTR register, making
  763.         set_r    REA_PTR_R    ;  room for more inbound packets
  764.         setport    BUFWIN_R
  765.         jmp    recv_loop
  766.  
  767. recv_sail_pop:    add    sp, ENET_HDR    ; pop the Ethernet-2 header from stack
  768.  
  769. recv_sail_it:    ; rid ourselves of this frame the hard way: by resetting the
  770.         ;   DMA, in addition to our own bookkeeping stuff
  771.         loadport
  772.         mov    ax, command_r    ; release the DMA FIFO
  773.         or    ax, FIFO_WRITE+DMA_INT_ACK
  774.         setw_r    COMSTAT_R
  775.         pop    cx        ; pop squirreled next HEADER POINTER
  776.         mov    rcv_ptr_copy, cx    ;  and make that the new pointer
  777.         mov    al, ch        ; update the REA PTR register, making
  778.         set_r    REA_PTR_R    ;  room for more inbound packets
  779.         setport    DMA_ADDR_R
  780.         jmp    recv_rcvptr
  781.  
  782. recv_done:    ; all inbound frames processed
  783.         loadport
  784.         mov    ax, command_r    ; release the DMA FIFO
  785.         or    ax, FIFO_WRITE+DMA_INT_ACK
  786.         setw_r    COMSTAT_R
  787.         ; restart a stalled receiver
  788.         getw_r    COMSTAT_R    ; grab the STATUS register
  789.         test    ax, RX_ON    ; receiver still on?
  790.         jnz    recv_done_1
  791. ifdef    DEBUG
  792.         inc    rx_restart
  793. endif
  794.         call    turn_rx_on
  795. recv_done_1:
  796.         ret
  797.  
  798.  
  799.     public    RECV_EXITING
  800. ; Part two of the ISR receive packet processing.  Called after interrupts
  801. ; have been acknowledged.  Only DS and AX have been saved, DS == CS and
  802. ; we're running on the original stack (i.e. not the private one).  On
  803. ; entry, interrupts are still disabled but it is possible to intelligently
  804. ; turn them back on.
  805. RECV_EXITING:
  806.         assume    ds:CODE
  807.         ret
  808.  
  809.  
  810.     public    RESET_INTERFACE
  811. ; Reset the interface.
  812. RESET_INTERFACE:
  813.         assume    ds:CODE
  814.         loadport
  815.         mov    ax, RESET
  816.         setw_r    CONFIG2_R
  817.         ; wait a good, long while
  818.         mov    ax, 1
  819.         call    set_timeout
  820. RESET_INTERFACE_1:
  821.         call    do_timeout
  822.         jnz    RESET_INTERFACE_1
  823. ;;;;        ; delay another 4 microseconds
  824. ;;;;        io_delay  io_delay_cnt    ; generic delay
  825. ;;;;        io_delay  io_delay_cnt    ; generic delay
  826.         ret
  827.  
  828.  
  829.     private    turn_rx_off
  830. ; Turn off the receiver portion of the device.  Undoes 'turn_rx_on'.
  831. turn_rx_off:
  832.         assume    ds:CODE
  833.         loadport
  834.         mov    ax, command_r
  835.         and    ax, NOT RX_INT_EN
  836.         or    ax, SET_RX_OFF
  837.         mov    command_r, ax
  838.         setw_r    COMSTAT_R
  839.         ret
  840.  
  841.  
  842.     private    turn_rx_on
  843. ; Turn on the receiver portion of the device.  Assumes the station address
  844. ; has already been programmed, receive ISR registered, etc.  Just brings it
  845. ; all to life on the wire.  Undone by 'turn_rx_off'.
  846. turn_rx_on:
  847.         assume    ds:CODE
  848.         loadport
  849.         ; load up Receive End Area Pointer
  850.         mov    al, TEA_INIT + 1
  851.         set_r    REA_PTR_R
  852.         ; load up the Receive Pointer Register
  853.         mov    ax, RCV_PTR
  854.         setw_r    RX_PTR_R
  855.         mov    rcv_ptr_copy, ax
  856.         ; now turn it on
  857.         mov    ax, command_r
  858.         and    ax, NOT SET_RX_OFF
  859.         or    ax, RX_INT_EN
  860.         mov    command_r, ax
  861.         or    ax, SET_RX_ON
  862.         setw_r    COMSTAT_R
  863.         ret
  864.  
  865.  
  866.     public    SEND_PKT
  867. ; Send one packet.  Entry with:
  868. ;    DS:SI    packet buffer to xmit
  869. ;    CX    packet length
  870. ;     ES:DI    upcall routine (0:0 if no upcall is desired) -- only supported
  871. ;        if the high-performance bit is set in 'driver_function' byte
  872. ; Returns:
  873. ;    NC    if OK
  874. ;       or
  875. ;    CY    if transmission error
  876. ;    DH    error code
  877. SEND_PKT:
  878.         assume    ds:nothing
  879. ifdef    DBGINT3
  880.         int    03h        ; Danger, Will Robinson!
  881. endif
  882.         mov    ax, ds        ; restore DS usage right here, saving
  883.         mov    es, ax        ;   it in ES (as we don't do upcalls)
  884.         mov    ax, cs
  885.         mov    ds, ax
  886.         assume     ds:CODE
  887.         cmp    cx, ENET_HDR    ; firewall against trivia
  888.         jae    SEND_PKT_1
  889.         jmp    send_pkt_ret
  890. SEND_PKT_1:
  891.         cmp    cx, GIANT    ; see if too big
  892.         jbe    SEND_PKT_2
  893.         jmp    send_pkt_NOSPACE
  894. SEND_PKT_2:
  895.         cmp    cx, RUNT    ; see if too small
  896.         jae    SEND_PKT_3    ; ... sounds like the Three Bears
  897.         mov    cx, RUNT    ; transmit at least this much
  898. SEND_PKT_3:
  899.         ; mask receiver interrupts (note the receiver is still
  900.         ;   running however) -- this also arbitrates use of the FIFO
  901.         push    cx        ; push stuff so MASKINT won't bite us
  902.         mov    al, INT_NO
  903.         call    MASKINT
  904.  
  905.         loadport
  906.         mov    ax, config1_r_copy    ; select BUFFER MEMORY in BUFWIN
  907.         or    ax, BUFFER_MEM_SEL
  908.         setw_r    CONFIG1_R
  909.  
  910.         ; check status of the previous transmission
  911.         cmp    transmit, 0    ; see if a transmit is incomplete
  912.         je    send_pkt_load
  913. send_pkt_wait:
  914.         loadport        ; synch for the loop
  915.         mov    ax, 3        ; address the TRANSMIT STATUS byte
  916.         setw_r    DMA_ADDR_R
  917.         mov    ax, command_r    ; set the FIFO to READ now, also
  918.         or    ax, FIFO_READ+TX_INT_ACK  ; ACKs any TX int bit
  919.         setw_r    COMSTAT_R
  920.         get_r    BUFWIN_R    ; get the STATUS byte
  921.         mov    bl, al        ; save the gotten STATUS byte
  922.         mov    ax, command_r    ; set the FIFO back to WRITE (aborts,
  923.         or    ax, FIFO_WRITE+DMA_INT_ACK  ; drains, ACKs FIFO int bit)
  924.         setw_r    COMSTAT_R
  925.         test    bl, HDR_DONE    ; check for transmit done
  926. ifdef    DEBUG
  927.         jnz    send_pkt_wait_1
  928.         inc    send_wait_c    ; count send completion waits
  929.         jmp    send_pkt_wait    ; loop
  930. send_pkt_wait_1:
  931. else
  932.         jz    send_pkt_wait    ; loop
  933. endif
  934.         ; done -- check for transmit error & count if so
  935.         test    bl, BABBLE_ERR+COLL_16_ERR
  936.         jz    send_pkt_load
  937.         call    COUNT_OUT_ERR    ; count the error
  938.  
  939. send_pkt_load:    ; load the new packet into the transmit area
  940.         pop    cx        ; revive stuff pushed for MASKINT
  941.         ; load up the transmit buffer -- allows only a single
  942.         ;   transmit (doesn't chain 'em); however, this transmission
  943.         ;   is overlapped with the preparation of the next
  944.         loadport        ; synch the state
  945.         xor    ax, ax        ; TRANSMIT NEXT HEADER word
  946.         setw_r    DMA_ADDR_R
  947.         mov    ax, cx        ; calculate xmit request length
  948.         add    ax, 4        ;   including 8005 garf
  949.         xchg    ah, al        ; SWAP
  950.         setw_r    BUFWIN_R
  951.         mov    al, PACKET_PRESENT+DATA_FOLLOWS ; TRANSMIT COMMAND byte
  952.         xor    ah, ah        ; TRANSMIT STATUS byte
  953.         setw_r    BUFWIN_R    ; both in one SWAPPED swoop
  954.  
  955.         ; semi-quick programmed output here -- direct use of macros
  956.         mov    ax, es        ; go back to DS-relative packet data
  957.         mov    ds, ax
  958.         assume    ds:nothing
  959.         cmp    io_16, 0    ; can do 16-bit i/o?
  960.         je    send_pkt_8bit
  961.         test    cx, 1        ; odd length?
  962.         jz    send_pkt_load_1
  963.         inc    cx        ; make even for 16-bit mode output
  964. send_pkt_load_1:
  965.         sar    cx, 1        ; /2: compute # of words to transfer
  966.         cmp    iowm_delay_cnt, 0  ; check for full-tilt boogie
  967.         jne    send_pkt_load_2    ; nope, need delays
  968.         rep    outsw        ; blow-out clearance i/o
  969.         jmp    SHORT send_pkt_xmt
  970. send_pkt_load_2:
  971.         mov    ax, [si]    ; Note: DS-relative packet here
  972.         out    dx, ax
  973.         io_delay iowm_delay_cnt    ; reduced delay w/i loop
  974.         inc    si
  975.         inc    si
  976.         loop    send_pkt_load_2
  977.         jmp    SHORT send_pkt_xmt    ; done w/ buffer load
  978.  
  979. send_pkt_8bit:    ; 8 bit packet load
  980.         cmp    iowm_delay_cnt, 0  ; check for full-tilt boogie
  981.         jne    UpHere_1    ; nope, need delays
  982.  
  983. ;the following replaces rep outsb, which doesn't work too well on 8088-based PCs
  984. ;;    rep    outsb            ; blow-out clearance i/o
  985.  
  986. UpHere:        lodsb            ; Note: DS-relative packet here
  987.         out    dx, al
  988.                 loop    UpHere
  989.  
  990.         jmp    SHORT send_pkt_xmt
  991. UpHere_1:
  992.         mov    al, [si]    ; Note: DS-relative packet here
  993.         out    dx, al
  994.         io_delay iowm_delay_cnt    ; reduced delay w/i loop
  995.         inc    si
  996.         loop    UpHere_1
  997.  
  998. send_pkt_xmt:    ; packet now loaded, finish up and transmit it
  999.         mov    ax, cs        ; restore our DS
  1000.         mov    ds, ax
  1001.         assume    ds:CODE
  1002.         ; set TRANSMIT POINTER (overlap as FIFO drains)
  1003.         xor    ax, ax        ; start chain at address 0
  1004.         setw_r    TX_PTR_R
  1005.         ; wait for DMA FIFO to drain
  1006.         fifo_wait
  1007.         ; now transmit it
  1008.         mov    ax, command_r    ; remove default transmitter off cmd
  1009.         and    ax, NOT SET_TX_OFF
  1010.         mov    command_r, ax
  1011.         or    ax, SET_TX_ON
  1012.         setw_r    COMSTAT_R    ; Send!
  1013.         mov    transmit, 1    ; note to check completion next time
  1014.         ; unmask receiver interrupts, releasing FIFO
  1015.         mov    al, INT_NO
  1016.         call    UNMASKINT
  1017. send_pkt_ret:
  1018.         clc            ; OK
  1019.         ret
  1020.  
  1021. send_pkt_NOSPACE:
  1022.         mov    dh, NO_SPACE
  1023.         stc            ; error
  1024.         ret
  1025.  
  1026.  
  1027.     public    SET_ADDRESS
  1028. ; Set the MAC station receiver address.  Entry with:
  1029. ;    DS:SI    the new MAC address to adopt
  1030. ;    CX    length of address at DS:SI
  1031. ; Returns:
  1032. ;    DS    restored to point at CODE segment
  1033. ;       plus
  1034. ;    NC    if OK
  1035. ;       or
  1036. ;    CY    if error
  1037. ;    DH    error code
  1038. SET_ADDRESS:
  1039.         assume    ds:nothing
  1040.         mov    ax, ds        ; undo the twisted DS usage
  1041.         mov    es, ax        ;   back to addressing our memory
  1042.         mov    ax, cs
  1043.         mov    ds, ax
  1044.          assume    ds:CODE
  1045.         cmp    cx, EADDR_LEN    ; check for proper address length
  1046.         jne    set_addr_BADADDRESS
  1047.         test    BYTE PTR es:[si], 1  ; deny broadcast or multicast
  1048.         jnz    set_addr_BADADDRESS
  1049.  
  1050. ;#        ; set the new station address (JLD)(9-25-91)
  1051.                 mov     ax, ds:[si][0]
  1052.                 mov     word ptr ds:station_0[0], ax
  1053.  
  1054.                 mov     ax, ds:[si][2]
  1055.                 mov     word ptr ds:station_0[2], ax
  1056.  
  1057.                 mov     ax, ds:[si][4]
  1058.                 mov     word ptr ds:station_0[4], ax
  1059.  
  1060.         ; disable receiver and/or transmitter
  1061.         call    rcvxmt_off    ; leaves COMMAND register on stack
  1062.  
  1063.         ; set the new station address
  1064.         loadport
  1065.         mov    ax, config1_r_copy    ; select STATION address reg 0
  1066.         or    ax, STATION_0_SEL
  1067.         setw_r    CONFIG1_R
  1068.         xor    ax, ax
  1069.         setw_r    DMA_ADDR_R
  1070.         setport    BUFWIN_R    ; fix access within the loop
  1071. SET_ADDRESS_1:
  1072.         mov    al, es:[si]    ; output bytes of the new address
  1073.         inc    si
  1074.         set_r    BUFWIN_R
  1075.         loop    SET_ADDRESS_1
  1076.  
  1077.         ; reenable the receiver if it was on before
  1078.         call    rcv_on        ; removes COMMAND register from stack
  1079.  
  1080.         clc            ; OK
  1081.         ret
  1082.  
  1083. set_addr_BADADDRESS:
  1084.         mov    dh, BAD_ADDRESS    ; improper address
  1085.         stc            ; error
  1086.         ret
  1087.  
  1088.  
  1089.     public    SET_MULTICAST_LIST
  1090. ; Set the multicast list.  Entry with:
  1091. ;    DS:SI    the list of multicast MAC addresses
  1092. ;    CX    number of addresses at DS:SI
  1093. ; Returns:
  1094. ;    NC    if OK
  1095. ;       or
  1096. ;    CY    if error
  1097. ;    DH    error code
  1098. SET_MULTICAST_LIST:
  1099.         assume    ds:CODE
  1100.         jmp    SHORT set_multicast_err    ; FOR NOW: no multicast support
  1101.         clc            ; OK
  1102.         ret
  1103. set_multicast_err:
  1104.         mov    dh, NO_MULTICAST
  1105.         stc            ; error
  1106.         ret
  1107.  
  1108.  
  1109.     public    TERMINATE
  1110. ; Terminate the packet driver.  Nothing special to do.
  1111. TERMINATE:
  1112.         assume    ds:CODE
  1113.         ret
  1114.  
  1115.     public    XMIT
  1116. ; Routine to process a queued transmission with the least possible latency.
  1117. ; Called immediately within the receive ISR.  The attempt here is to effect
  1118. ; back-to-back transmissions.  This routine may only use AX and DX freely
  1119. ; and is running whatever stack exists at interrupt time (not the private
  1120. ; one).  This routine isn't necessary on the 8005, because it can chain
  1121. ; transmissions (if anyone really cared).
  1122. XMIT:
  1123.         assume    ds:nothing
  1124.         ret
  1125.  
  1126.  
  1127.     include timeout.asm
  1128.  
  1129.  
  1130. ; Everything above this line is resident upon successful load.
  1131.  
  1132.     private    END_RESIDENT
  1133. END_RESIDENT    label    byte
  1134.  
  1135. ; Everything below this line is discarded upon installation.
  1136.  
  1137.     public    USAGE_MSG
  1138. USAGE_MSG    db    "usage: davidsys [-n] [-d] [-w] <packet_int_no> <int_no> <io_addr> <delay_mult>",CR,LF,'$'
  1139.  
  1140.     public    COPYRIGHT_MSG
  1141. COPYRIGHT_MSG    db    "Packet driver for the Ether-T PC/AT ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,".",'0'+s8005_version,CR,LF
  1142.         db    "Portions Copyright 1991 DAVID Systems, Inc and Marc S Dye",CR,LF,'$'
  1143.  
  1144. badint_msg    db    "Specified device interrupt not supported for"
  1145.         db    " your installation",CR,LF,'$'
  1146. int8_msg    db    " Try: 2, 3, 4, 5, 6, or 7",CR,LF,'$'
  1147. int16_msg    db    " Try: 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, or 15"
  1148.         db      CR,LF,'$'
  1149. inttimedout_msg    db    "Timed out awaiting device test interrupt",CR,LF,'$'
  1150. nodev_msg    db    "No device found at specified i/o address",CR,LF,'$'
  1151. setaddr_msg    db    "Unable to set initial station address",CR,LF,'$'
  1152.  
  1153. delay_mult_name    db    "Delay multipler (x10) ",'$'
  1154. int_no_name    db    "Interrupt number ",'$'
  1155. io_addr_name    db    "I/O port ",'$'
  1156.  
  1157. ifdef    DEBUG
  1158. count_del_name    db    "Incremental i/o delay spin (nsec x10) ",'$'
  1159. delay_del_name    db    "Basic i/o delay (nsec x100) ",'$'
  1160. io_delay_name    db    "I/O delay (spins) ",'$'
  1161. iowm_delay_name    db    "I/O write memory delay (spins) ",'$'
  1162. null_bias_name    db    "Null (overhead) cost (nsec x100) ",'$'
  1163. null_spin_name    db    "Null spin count ",'$'
  1164. ref_spin_name    db    "Reference spin count ",'$'
  1165. unit_spin_name    db    "Single spin count ",'$'
  1166. endif
  1167.  
  1168.     private    int_map
  1169. ; Interrupt number to Ether-T PC/AT configuration register code mapping table
  1170.         ;     0    1    2    3    4    5    6    7
  1171. int_map        db    00h, 00h, 02h, 01h, 03h, 04h, 05h, 06h
  1172.         ;     8    9   10   11   12   13   14   15
  1173.         db    00h, 02h, 07h, 08h, 09h, 00h, 0Ah, 0Bh
  1174.  
  1175. REF_DELAY    equ    64
  1176.  
  1177.     private    count_delay
  1178. count_delay    dw    ?, 0        ; # of 10 nsecs in each io_delay spin
  1179.     private    delay_delay
  1180. delay_delay    dw    ?, 0        ; # of 100 nsecs in the basic io_delay
  1181.     private    null_bias
  1182. null_bias    dw    ?, 0        ; # of 100 nsecs in a null spin
  1183.     private    null_spins
  1184. null_spins    dw    ?, 0        ; # of spins for without io_delay macro
  1185.     private    ref_spins
  1186. ref_spins    dw    ?, 0        ; # of spins for io_delay of 1+REF_DELAY
  1187.     private    test_delay
  1188. test_delay    dw    ?        ; holding tank for current sample count
  1189.     private    unit_spins
  1190. unit_spins    dw    ?, 0        ; # of spins for io_delay of 1
  1191.  
  1192.  
  1193. ; macro to sample timer zero's counter register
  1194. timer0_sample    macro
  1195.         xor    al, al        ; latch timer zero counter 
  1196.         out    43h, al
  1197.         in    al, 40h        ; sample timer zero counter
  1198.         mov    ah, al
  1199.         in    al, 40h
  1200.         xchg    ah, al
  1201.         endm
  1202.  
  1203.  
  1204.     private    calibrate_one
  1205. calibrate_one:
  1206.         assume    ds:CODE
  1207.         mov    test_delay, ax
  1208.         ; find the timer near zero
  1209.         mov    cx, 100h
  1210. calibrate_one_1:
  1211.         timer0_sample
  1212.         cmp    ax, cx
  1213.         ja    calibrate_one_1
  1214.         ; now find the timer above that value (after wrapping to max)
  1215. calibrate_one_2:
  1216.         timer0_sample
  1217.         cmp    ax, cx
  1218.         jbe    calibrate_one_2
  1219.         ; wait till it gets to the one quarter point
  1220.         mov    cx, 0C000h
  1221. calibrate_one_3:
  1222.         timer0_sample
  1223.         cmp    ax, cx
  1224.         ja    calibrate_one_3
  1225.         ; calibration time - disable interrupts, watch for half a
  1226.         ;  clock period to elapse
  1227.         pushf
  1228.         cli
  1229.         xor    bx, bx
  1230.         mov    cx, 4000h
  1231.         cmp    test_delay, 0        ; see if measuring overhead?
  1232.         jne    calibrate_io
  1233.         ; calibrating the overhead of this timing stuff only
  1234. calibrate_one_4:
  1235.         inc    bx
  1236.         jc    calibrate_exit        ; overflow - exit w/ 0
  1237.         timer0_sample
  1238.         cmp    ax, cx
  1239.         ja    calibrate_one_4
  1240.         jmp    SHORT calibrate_exit
  1241. calibrate_io:    io_delay  test_delay
  1242.         inc    bx
  1243.         jc    calibrate_exit        ; overflow - exit w/ 0
  1244.         timer0_sample
  1245.         cmp    ax, cx
  1246.         ja    calibrate_io
  1247. calibrate_exit:    popf
  1248.         mov    ax, bx
  1249.         ret
  1250.  
  1251.  
  1252.     private    calibrate_delay
  1253. calibrate_delay:
  1254.         assume    ds:CODE
  1255.         ; if user wanted no delays, skip all this stuff
  1256.         cmp    delay_mult, 0
  1257.         jne    calibrate_delay_1
  1258.         xor    ax, ax            ; normalize to zero
  1259.         jmp    calibrate_store
  1260. calibrate_delay_1:
  1261.         ; calibrate the overhead of the time sampling loop
  1262.         xor    ax, ax
  1263.         call    calibrate_one
  1264.         or    ax, ax
  1265.         jz    calibrate_dj        ; can't time -- default it all
  1266.         mov    null_spins, ax
  1267. ifdef    DEBUG
  1268.         mov    di, OFFSET null_spins
  1269.         mov    dx, OFFSET null_spin_name
  1270.         call    PRINT_NUMBER
  1271. endif
  1272.         ; calibrate a unit (single spin) loop
  1273.         mov    ax, 1
  1274.         call    calibrate_one
  1275.         or    ax, ax
  1276.         jz    calibrate_dj        ; can't time -- default it
  1277.         mov    unit_spins, ax
  1278. ifdef    DEBUG
  1279.         mov    di, OFFSET unit_spins
  1280.         mov    dx, OFFSET unit_spin_name
  1281.         call    PRINT_NUMBER
  1282.         mov    ax, unit_spins    ; reload AX
  1283. endif
  1284.         cmp    null_spins, ax        ; ensure null >= unit
  1285.         jb    calibrate_dj        ; bogonic -- default it
  1286.         ; now one with some teeth in it
  1287.         mov    ax, 1+REF_DELAY
  1288.         call    calibrate_one
  1289.         or    ax, ax
  1290.         jz    calibrate_dj        ; can't time -- default it all
  1291.         mov    ref_spins, ax
  1292. ifdef    DEBUG
  1293.         mov    di, OFFSET ref_spins
  1294.         mov    dx, OFFSET ref_spin_name
  1295.         call    PRINT_NUMBER
  1296.         mov    ax, ref_spins        ; reload AX
  1297. endif
  1298.         cmp    unit_spins, ax        ; ensure unit > ref
  1299.         ja    calibrate_dj_1
  1300. calibrate_dj:    jmp    SHORT calibrate_def    ; bogonic -- default it
  1301. calibrate_dj_1:
  1302.  
  1303.         ; now do the math - compute the overhead of the timing code
  1304.         ;  (in units of 100 nsec)
  1305.         mov    cx, null_spins
  1306.         call    compute_100nsecs
  1307.         jc    calibrate_def
  1308.         mov    null_bias, ax
  1309. ifdef    DEBUG
  1310.         mov    di, OFFSET null_bias
  1311.         mov    dx, OFFSET null_bias_name
  1312.         call    PRINT_NUMBER
  1313. endif
  1314.         ; compute cost of the basic i/o delay macro (in units of
  1315.         ;  100 nsec)
  1316.         mov    cx, unit_spins
  1317.         call    compute_100nsecs
  1318.         jc    calibrate_def
  1319.         sub    ax, null_bias
  1320.         mov    delay_delay, ax
  1321. ifdef    DEBUG
  1322.         mov    di, OFFSET delay_delay
  1323.         mov    dx, OFFSET delay_del_name
  1324.         call    PRINT_NUMBER
  1325. endif
  1326.         ; compute cost of the reference spin in the i/o delay
  1327.         ;  macro (this time, in units of 10 nsec)
  1328.         mov    cx, ref_spins
  1329.         call    compute_100nsecs
  1330.         jc    calibrate_def
  1331.         sub    ax, null_bias
  1332.         sub    ax, delay_delay        ; now delay for REF_COUNT spins
  1333.         mov    cx, 10
  1334.         mul    cx
  1335.         jnc    calibrate_dj_2
  1336.         ; this machine is *sooo* slow, a minimum delay is fine
  1337.         mov    ax, 1
  1338.         jmp    SHORT calibrate_store
  1339. calibrate_dj_2:
  1340.         mov    cx, REF_DELAY
  1341.         div    cx
  1342.         mov    count_delay, ax
  1343. ifdef    DEBUG
  1344.         mov    di, OFFSET count_delay
  1345.         mov    dx, OFFSET count_del_name
  1346.         call    PRINT_NUMBER
  1347. endif
  1348.  
  1349.         ; now, see if basic i/o delay (w/o extra spins) is enough
  1350.         mov    bx, 1            ; basic macro includes one spin
  1351.         mov    ax, delay_delay
  1352.         sub    ax, 22            ; >= 2.2 usec ?
  1353.         jae    calibrate_dj_3
  1354.         neg    ax            ; correct sign of residual
  1355.         mov    cx, 10            ; scale to 10 nsec units
  1356.         mul    cx
  1357.         jc    calibrate_def
  1358.         div    count_delay
  1359.         inc    ax
  1360.         add    bx, ax            ; back into spin count result
  1361. calibrate_dj_3:
  1362.         mov    ax, bx            ; the calibrated basic result
  1363.         jmp    SHORT calibrate_store
  1364.  
  1365. calibrate_def:    ; this processor is *sooo* fast that we can't calibrate it!?
  1366.         ; just use a conservative default (should be good to about a
  1367.         ;  400MHz 80486)
  1368.         mov    ax, 120
  1369.  
  1370.         ; scale the delay by the user-request multiplier (if any)
  1371. calibrate_store:
  1372.         mul    delay_mult        ; a tens multiple
  1373.         mov    cx, 10            ; so reduce / 10
  1374.         div    cx            ; allowed to be zero
  1375.         mov    io_delay_cnt, ax
  1376.         ; compute the .9 usec 'iowm_delay_cnt'
  1377.         mov    cx, 9
  1378.         mul    cx
  1379.         mov    cx, 20
  1380.         div    cx
  1381.         mov    iowm_delay_cnt, ax
  1382.         ret
  1383.  
  1384.  
  1385.     private    compute_100nsecs
  1386. ; Given a value in CX (representing spin counter during a 1/36.04 timing
  1387. ;  run), compute the number of hundreds of nanoseconds per unit spin. Return
  1388. ;  result in AX, or set CY and return if algorithm won't scale.
  1389. compute_100nsecs:
  1390.         assume    ds:CODE
  1391.         mov    ax, 9            ; compute spins * 9 (36.04/4)
  1392.         mul    cx
  1393.         jc    compute_100n_err    ; won't fit -- return error
  1394.         mov    cx, ax            ; prepare for division
  1395.         mov    dx, 26h            ; put 2,500,000 into DX,AX
  1396.         mov    ax, 25a0h
  1397.         div    cx            ; compute 10M / (spins*36.04)
  1398.         clc
  1399.         ret
  1400. compute_100n_err:
  1401.         ret
  1402.  
  1403.  
  1404.     public    ETOPEN
  1405. ; Perform initial open of the device.  Called only once: immediately prior to
  1406. ; hooking the packet driver service interrupt and TSRing.  Device interrupts
  1407. ; are to be hooked (if this routine deems reasonable to do so).  No registers
  1408. ; are given on entry.  On return:
  1409. ;    NC    if OK
  1410. ;    DX    offset of the end of the resident portion of the driver
  1411. ;       or
  1412. ;    CY    if error
  1413. ETOPEN:
  1414.         assume    ds:CODE
  1415. ifdef    DBGINT3
  1416.         int    03h        ; Danger, Will Robinson!
  1417. endif
  1418.         ; calibrate the i/o delays needed
  1419.         call    calibrate_delay
  1420. ifdef    DEBUG
  1421.         mov    di, OFFSET io_delay_cnt
  1422.         mov    dx, OFFSET io_delay_name
  1423.         call    PRINT_NUMBER
  1424.         mov    di, OFFSET iowm_delay_cnt
  1425.         mov    dx, OFFSET iowm_delay_name
  1426.         call    PRINT_NUMBER
  1427. endif
  1428.  
  1429.         ; test for access to the device; check for 16-bit i/o
  1430.         call    try_io
  1431.         jnc    ETOPEN_1
  1432.         jmp    etopen_err
  1433. ETOPEN_1:
  1434.         ; try out the interrupt channel & leave hooked if successful
  1435.         call    try_interrupt
  1436.         jnc    ETOPEN_2
  1437.         jmp    etopen_err
  1438. ETOPEN_2:
  1439.         ; get the PROM Ethernet address
  1440.         call    RESET_INTERFACE    ; reset the device (again!)
  1441.         loadport
  1442.         mov    ax, command_r    ; everything still off
  1443.         or    ax, FIFO_WRITE
  1444.         setw_r    COMSTAT_R
  1445.         xor    ax, ax        ; reset the DMA address to 0
  1446.         setw_r    DMA_ADDR_R
  1447.         mov    ax, config1_r_copy    ; select the PROM
  1448.         or    ax, PROM_SEL
  1449.         setw_r    CONFIG1_R
  1450.         mov    ax, config2_r_copy    ; blast the watchdog
  1451.         or    ax, KILL_WATCHDOG
  1452.         setw_r    CONFIG2_R
  1453.         mov    cx, EADDR_LEN    ; allocate some space for the address
  1454.         sub    sp, cx
  1455.         mov    bp, sp
  1456.         setport    BUFWIN_R    ; fix access within the loop
  1457. ETOPEN_3:
  1458.         get_r    BUFWIN_R    ; next byte of PROM Ethernet address
  1459.         mov    [bp], al
  1460.         inc    bp
  1461.         loop    ETOPEN_3
  1462.  
  1463.         ; set the PROM address as the default STATION 0 address
  1464.         call    RESET_INTERFACE    ; reset the device (yet again!)
  1465.  
  1466.         mov    cx, EADDR_LEN    ; size of Ethernet address
  1467.         mov    si, sp        ; PROM Ethernet address atop stack
  1468.         call    SET_ADDRESS
  1469.         add    sp, EADDR_LEN    ; pop Ethernet address from the stack
  1470.  
  1471.         ; load up Transmit End Area Pointer
  1472.         loadport
  1473.         mov    ax, config1_r_copy
  1474.         or    ax, TEA_SEL
  1475.         setw_r    CONFIG1_R
  1476.         mov    al, TEA_INIT
  1477.         set_r    BUFWIN_R
  1478.  
  1479.         ; set up a few other default goodies once only here:
  1480.         ;  config 1 :    STATION 0 address (Matchmode by 'rcv_mode_3')
  1481.         ;  config 2 :    defaults are OK
  1482.         or    config1_r_copy, STATION_0_EN
  1483.         mov    ax, config1_r_copy
  1484.         setw_r    CONFIG1_R
  1485.  
  1486.         ; we're go now -- wake up and smell the roses!
  1487.         and    command_r, NOT SET_RX_OFF
  1488.         ; reload the CARD CONFIGURATION register
  1489.         mov    ax, config1_r_copy    ; select CARD CONFIGURATION register
  1490.         or    ax, CARD_CONFIG_SEL
  1491.         setw_r    CONFIG1_R
  1492.         mov    al, cardconfig_r
  1493.         set_r    BUFWIN_R    ; writes CARD CONFIGURATION register
  1494.         ; turn on the receiver now, in (default) mode 3
  1495.         call    rcv_mode_3
  1496.  
  1497.         ; tell the caller where resident memory ends
  1498.         mov    dx, OFFSET END_RESIDENT
  1499.         clc            ; OK
  1500.         ret
  1501.  
  1502. etopen_err:
  1503.         stc            ; error
  1504.         ret
  1505.  
  1506.  
  1507.     public    PARSE_ARGS
  1508. ; Parse the device-specific portion of the invokation command line (after
  1509. ; the packet driver vector number).  Entry with:
  1510. ;    DS:SI    residual command line
  1511. ; Can emit device-specific bitches as necessary (using DOS i/o) and exit
  1512. ; without returning.  If it returns:
  1513. ;    NC    if OK
  1514. ;       or
  1515. ;    CY    if usage error
  1516. ; Returning w/ carry set will cause a usage error, then exit without further
  1517. ; processing.
  1518. PARSE_ARGS:
  1519.         assume    ds:CODE
  1520.         mov    di, OFFSET INT_NO
  1521.         call    GET_NUMBER
  1522.         mov    di, OFFSET IO_ADDR
  1523.         call    GET_NUMBER
  1524.         mov    di, OFFSET delay_mult
  1525.         call    GET_NUMBER
  1526.         clc            ; OK
  1527.         ret
  1528.  
  1529.  
  1530.     public    PRINT_PARAMETERS
  1531. ; Spew out all of the configuration parameters to the console device.
  1532. ; Called within the main program, just prior to deciding to TSR.  Should
  1533. ; dump out each device-specific parameter, parsed by PARSE_ARGS (just to
  1534. ; make the user warm-and-fuzzy I suppose...)  Entry with:
  1535. ;    no special register contents
  1536. ; Returns:
  1537. ;    nothing
  1538. PRINT_PARAMETERS:
  1539.         assume    ds:CODE
  1540.         mov    di, OFFSET INT_NO
  1541.         mov    dx, OFFSET int_no_name
  1542.         call    PRINT_NUMBER
  1543.         mov    di, OFFSET IO_ADDR
  1544.         mov    dx, OFFSET io_addr_name
  1545.         call    PRINT_NUMBER
  1546.         mov    di, OFFSET delay_mult
  1547.         mov    dx, OFFSET delay_mult_name
  1548.         call    PRINT_NUMBER
  1549.         ret
  1550.  
  1551.  
  1552.     private    try_interrupt
  1553. ; try out the receiver interrupt (once at the outset); in the process,
  1554. ; sets up the CARD CONFIGURATION register
  1555. try_interrupt:
  1556.         assume ds:CODE
  1557.         call    RESET_INTERFACE
  1558.         loadport
  1559.         mov    ax, config1_r_copy    ; program CARD CONFIGURATION register
  1560.         or    ax, CARD_CONFIG_SEL
  1561.         setw_r    CONFIG1_R
  1562.         ; map interrupt number to card config enumeration value
  1563.         mov    bx, WORD PTR INT_NO
  1564.         mov    al, [bx + OFFSET int_map]
  1565.         or    al, al
  1566.         jz    try_int_badint_err
  1567.         ; check for 16-bit i/o usage; include in card config value
  1568.         cmp    io_16, 0
  1569.         je    try_interrupt_1
  1570.         or    al, SET_16BITMODE_M
  1571. try_interrupt_1:
  1572.         set_r    BUFWIN_R    ; writes CARD CONFIGURATION register
  1573.         mov    cardconfig_r, al  ; save soft-copy of this
  1574.         ; install the 'recv_isr' handler
  1575.         mov    int_test, 1    ; flag that we're testing only
  1576.         call    SET_RECV_ISR
  1577.         ; cause a receiver interrupt
  1578.         loadport
  1579.         mov    ax, command_r    ; SET_RX_OFF in here now
  1580.         or    ax, RX_INT_EN+SET_RX_ON
  1581.         setw_r    COMSTAT_R    ; Interrupt!
  1582. ;# Compaq DOS leaves CPU ints disabled!
  1583.                 sti
  1584.         mov    ax, 1        ; wait one tick
  1585.         call    set_timeout
  1586. try_interrupt_2:
  1587.         call    do_timeout
  1588.         jz    try_int_timedout
  1589.         cmp    int_tested, 0    ; did it happen?
  1590.         je    try_interrupt_2
  1591.         ; the interrupt worked -- leave w/ the receiver off, the
  1592.         ;   ISR hooked but masked
  1593.         mov    ax, command_r    ; SET_RX_OFF in here now
  1594.         setw_r    COMSTAT_R    ; shut up!
  1595.         mov    al, INT_NO
  1596.         call    MASKINT
  1597.         mov    int_test, 0    ; from now on, it's the real thing
  1598.         clc            ; OK
  1599.         ret
  1600.  
  1601. try_int_timedout:
  1602.         ; timed-out (bummer dude!) -- turn receiver back off
  1603.         mov    ax, command_r    ; SET_RX_OFF in here now
  1604.         or    ax, RX_INT_ACK     ; just in case ...
  1605.         setw_r    COMSTAT_R    ; shut up!
  1606.         ; deregister handler and boogie
  1607.         ;   This should be a standard call -- I've asked Russ ...
  1608.         mov    al, INT_NO
  1609.         add    al, 8
  1610.         cmp    al, 8+8        ; is it a slave 8259 interrupt?
  1611.         jb    try_int_timedout_1; no.
  1612.         add    al, 70h - (8+8)    ; map it to the real interrupt
  1613. try_int_timedout_1:
  1614.         push    ds
  1615.         assume    ds:nothing
  1616.         lds    dx, THEIR_ISR
  1617.         mov    ah, 25h
  1618.         int    21h
  1619.         pop    ds
  1620.         assume    ds:CODE
  1621.         mov    dx, OFFSET inttimedout_msg    
  1622.         jmp    SHORT try_int_err
  1623. try_int_badint_err:
  1624.         mov    dx, OFFSET badint_msg
  1625.         mov    ah, 9        ; blab to the user
  1626.         int    21h
  1627.         cmp    io_16, 0    ; tell him/her/it what's legit
  1628.         jne    try_int_badint_err_1
  1629.         mov    dx, OFFSET int8_msg
  1630.         jmp    SHORT try_int_err
  1631. try_int_badint_err_1:
  1632.         mov    dx, OFFSET int16_msg
  1633. try_int_err:
  1634.         mov    ah, 9        ; blab to the user
  1635.         int    21h
  1636.         stc            ; error
  1637.         ret
  1638.  
  1639.  
  1640.     private    try_io
  1641. ; try out i/o to the device; in the process, determines if 16-bit i/o is OK
  1642. ; NOTE: This code was transliterated from the C source for DAVID's NDIS driver.
  1643. ;   In the absence of any written documentation on the CARD CONFIGURATION
  1644. ;   register, the many magic numbers herein remain a mystery.
  1645. try_io:
  1646.         assume ds:CODE
  1647.         call    RESET_INTERFACE
  1648.         mov    command_r, SET_TX_OFF+SET_RX_OFF+SET_DMA_OFF
  1649.         loadport
  1650.         mov    ax, config1_r_copy    ; select CARD CONFIGURATION register
  1651.         or    ax, CARD_CONFIG_SEL
  1652.         set_r    CONFIG1_R    ; BYTE-size only here!
  1653.         ; first taunting of the device ...
  1654.         mov    al, 05h        ; C sez: "4 bit is LSBS value"
  1655.         set_r    BUFWIN_R    ;        " ... and ... "
  1656.         get_r    BUFWIN_R    ; C sez: "comes back in the 4 MSBs"
  1657.         and    al, 0F0h
  1658.         cmp    al, 50h        ; this has to compare
  1659.         jne    try_io_err
  1660.         ; second taunting of the device ...
  1661.         mov    al, 0Ah        ; "Your mother was a hamster ..."
  1662.         set_r    BUFWIN_R
  1663.         get_r    BUFWIN_R    ; "... and your father smelt of"
  1664.         and    al, 0F0h    ;     "ELDERBERRIES!"
  1665.         cmp    al, 0A0h
  1666.         jne    try_io_err
  1667.         ; now for something completely different -- ask the CARD
  1668.         ;   CONFIGURATION register if it's plugged into an 8- or
  1669.         ;   16-bit slot; mark it well
  1670.         get_r    BUFWIN_R
  1671.         and    al, 1        ; bit on means 8-bit slot
  1672.         xor    al, 1        ; complement sense for 'io_16'
  1673.         mov    io_16, al
  1674.         jz    try_io_1
  1675.         ; set-up 16-bit versions of word i/o functions
  1676.         ; N.B. From this point forward, we MUST to 16 bit i/o
  1677.         ;   on 16 bit objects if the card told us to!
  1678.         mov    inw_fn, OFFSET inw_8005   ; input function
  1679.         mov    outw_fn, OFFSET outw_8005 ; output function
  1680. try_io_1:
  1681.         clc            ; OK
  1682.         ret
  1683.  
  1684. try_io_err:
  1685.         mov    dx, OFFSET nodev_msg
  1686.         mov    ah, 9        ; blab to the user
  1687.         int    21h
  1688.         stc            ; error
  1689.         ret    ; "Now go away or I shall taunt you a second time-uh!"
  1690.  
  1691.  
  1692. CODE        ends
  1693.  
  1694.         end
  1695.  
  1696.  
  1697. ; eof
  1698.